#include "manipulatorbase.h"
#include "actorbase.h"
#include "effectcontainermanager.h"
#include "layersmanager.h"
#include "environmentlayeractor.h"
#include <osgViewer\Viewer>

namespace ControlCenter
{
	ManipulatorBase::ManipulatorBase():_lostFocus(false),_usePickManager(true)
		,_boolFocusInGraphWin(true),_viewType(VIEW_TYPE_EDITER),_maxradius(FLT_MAX),_cameraInSky(false)
		,_environmentLayer(NULL),_view(NULL)
	{
		_operatorObjectVector.clear();
		_operateObjType = GET_TYPE_INT_FROM_STRING(CLASS_DEVICE);
	}

	ManipulatorBase::~ManipulatorBase()
	{}

	void ManipulatorBase::setOperatorObjectVector(QVector<CoreBase::ActorBase*> objvector)
	{
		_operatorObjectVector.clear();
		_operatorObjectVector = objvector;
	}

	void ManipulatorBase::addOperatorObject(CoreBase::ActorBase* obj)
	{
		_operatorObjectVector.push_back(obj);
	}

	QVector<CoreBase::ActorBase*>	ManipulatorBase::getOperatorObjectVector()
	{
		return _operatorObjectVector;
	}

	void ManipulatorBase::setLookAt(const osg::Vec3& eye,const osg::Vec3& center,const osg::Vec3& up,float distance,bool rightaway)
	{}

	void ManipulatorBase::getLookAt(osg::Vec3& eye,osg::Vec3& center,osg::Vec3& up,float& distance)
	{}

	void ManipulatorBase::useCollisionCamera(bool use)
	{
		_useCollisionCamera = use;
	}

	void ManipulatorBase::flushMouseEventStack()
	{
		_ga_t1 = NULL;
		_ga_t0 = NULL;
	}

	void ManipulatorBase::flushKeyEventStack()
	{
		_key_t1 = NULL;
		_key_t0 = NULL;
	}

	void ManipulatorBase::addMouseEvent(const osgGA::GUIEventAdapter& ea)
	{
		_ga_t1 = _ga_t0;
		_ga_t0 = &ea;
	}

	void ManipulatorBase::addKeyEvent(const osgGA::GUIEventAdapter& ea)
	{
		_key_t1 = _key_t0;
		_key_t0 = &ea;
	}

	bool ManipulatorBase::graphWindowHaveFocus(const int x,const int y)
	{
		bool wmhave = VrDataCore::EffectContainerManager::GetInstance().hudWindowManagerHaveFocus(x,y);
		return !wmhave;
	}

	void ManipulatorBase::initManipulatorStart(const osg::Vec3& eye,const osg::Vec3& center,const osg::Vec3& up)
	{
		_homeEye = eye;
		_homeCenter = center;
		_homeUp = up;
	}

	void ManipulatorBase::setToolAction(ActionData* action)
	{
		_action = action->_actionKey;
	}

	int ManipulatorBase::intersectionTestSphereWithSegment(double segx1, double segy1, double segz1,
		double segx2, double segy2, double segz2,double sx, double sy, double sz, double r,
		double *ix, double *iy, double *iz)
	{
		const double i = segx2 - segx1;
		const double j = segy2 - segy1;
		const double k = segz2 - segz1;
		const double a = i * i + j * j + k * k;
		const double b = 2.0 * ( i * ( segx1 - sx ) + j * ( segy1 - sy ) + k * ( segz1 - sz) );
		const double c = sx * sx + sy * sy + sz * sz + segx1 * segx1 + segy1 * segy1 + segz1 * segz1
			- 2.0 * ( sx * segx1 + sy * segy1 + sz * segz1 ) - r * r;
		const double d = b * b - 4 * a * c;
		if (d < 0 || d == 0.0 && a == 0.0)
			return 0;
		if (d > -0.0000001 && d < 0.0000001){
			const double t = ( (a > -0.0000001 && a < 0.0000001 ) ? 0.0 : -b / (2.0 * a) );
			ix[0] = ix[1] = segx1 + t * i;
			iy[0] = iy[1] = segy1 + t * j;
			iz[0] = iz[1] = segz1 + t * k; 
			return 1;
		}
		else{
			const double t0 = ( (a > -0.0000001 && a < 0.0000001 ) ? 0.0 : (-b + sqrt(d)) / (2.0 * a) );
			const double t1 = ( (a > -0.0000001 && a < 0.0000001 ) ? 0.0 : (-b - sqrt(d)) / (2.0 * a) );
			if (t0 < t1){
				ix[0] = segx1 + t0 * i;
				iy[0] = segy1 + t0 * j;
				iz[0] = segz1 + t0 * k;
				ix[1] = segx1 + t1 * i;
				iy[1] = segy1 + t1 * j;
				iz[1] = segz1 + t1 * k;
			}
			else{
				ix[0] = segx1 + t1 * i;
				iy[0] = segy1 + t1 * j;
				iz[0] = segz1 + t1 * k;
				ix[1] = segx1 + t0 * i;
				iy[1] = segy1 + t0 * j;
				iz[1] = segz1 + t0 * k;
			}
			return 2;
		}  
	}

	bool ManipulatorBase::testInSky(const osg::Matrixd& before,const osg::Matrixd& after,osg::Vec3& intersectz,bool& movein)
	{
		if(_environmentLayer == NULL)
		{
			_environmentLayer = dynamic_cast<VrDataCore::EnvironmentLayerActor*>(VrDataCore::LayersManager::GetInstance().getEnvironmentLayer());
			bool enable;
			QString type,active;
			_environmentLayer->getSkyDomeEnable(enable,type,active,_maxradius);
			_maxradius = _maxradius*0.5f;
		}
		osg::Vec3 skypos = _environmentLayer->getSkyOffset();
		if((after.getTrans() - skypos).length()>_maxradius)
		{
			double x[2], y[2], z[2] = {-1,-1};
			intersectionTestSphereWithSegment(after.getTrans().x(),after.getTrans().y(),after.getTrans().z(),
				skypos.x(),skypos.y(),skypos.z(),skypos.x(),skypos.y(),skypos.z(),_maxradius,x,y,z);
			for(int i=0;i<2;++i)
			{
				if(z[i]>0)
				{
					intersectz = osg::Vec3(x[i],y[i],z[i]);
				}
			}
			if((after.getTrans() - skypos).length()>(before.getTrans() - skypos).length())
				movein = false;
			else
				movein = true;
			return false;
		}
		else
			return true;
	}
}